package com.choosefine.paycenter.account.service.impl;

import com.choosefine.paycenter.account.dao.AccountBankcardMapper;
import com.choosefine.paycenter.account.dto.AccountBankcardDto;
import com.choosefine.paycenter.account.dto.AccountBankcardSetUBankCodeAndNameDto;
import com.choosefine.paycenter.account.dto.AccountCompanyBankcardVerifyDto;
import com.choosefine.paycenter.account.enums.BankcardTypeEnum;
import com.choosefine.paycenter.account.model.AccountBankcard;
import com.choosefine.paycenter.account.model.BankcardBin;
import com.choosefine.paycenter.account.service.AccountBankcardService;
import com.choosefine.paycenter.account.service.AccountService;
import com.choosefine.paycenter.account.service.BankcardBinService;
import com.choosefine.paycenter.channel.ccb.api.impl.CCBPayConfigStorage;
import com.choosefine.paycenter.channel.ccb.entity.wlpt.req.CCB6W1101TxReq;
import com.choosefine.paycenter.channel.ccb.entity.wlpt.req.CCB6W8020TxReq;
import com.choosefine.paycenter.channel.ccb.entity.wlpt.req.body.CCB6W1101TxReqBody;
import com.choosefine.paycenter.channel.ccb.entity.wlpt.req.body.CCB6W8020TxReqBody;
import com.choosefine.paycenter.channel.ccb.entity.wlpt.res.CCB6W1101TxRes;
import com.choosefine.paycenter.channel.ccb.entity.wlpt.res.CCB6W8020TxRes;
import com.choosefine.paycenter.channel.ccb.utils.CCBWlptUtils;
import com.choosefine.paycenter.common.constants.ExceptionCodeConstants;
import com.choosefine.paycenter.common.constants.ExceptionMessageConstants;
import com.choosefine.paycenter.common.exception.BusinessException;
import com.choosefine.paycenter.common.utils.MessageSourceUtils;
import com.choosefine.paycenter.common.utils.SerialNumberUtils;
import com.choosefine.paycenter.pay.service.BankService;
import com.choosefine.paycenter.pay.service.ChannelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

/**
 * Comments：银行卡管理
 * Author：DengYouyi
 * Create Date：2017/3/8
 * Modified By：
 * Modified Date：
 * Why & What is modified：
 * Version：v1.0
 */
@Slf4j
@Service
public class AccountBankcardServiceImpl implements AccountBankcardService{
    @Autowired
    private AccountBankcardMapper accountBankcardMapper;

    @Autowired
    private AccountService accountService;

    @Autowired
    private CCBWlptUtils ccbWlptUtils;

    @Autowired
    private CCBPayConfigStorage ccbPayConfigStorage;

    @Value("${accountBankcard.verifyRandomMoneyUpLimit}")
    private double verifyRandomMoneyUpLimit;

    @Autowired
    private SerialNumberUtils serialNumberUtils;

    @Autowired
    private MessageSourceUtils localeMessageSourceUtils;

    @Autowired
    private ChannelService channelService;

    @Autowired
    private BankcardBinService bankcardBinService;

    @Autowired
    private BankService bankService;

    private final static String[] TRANSACTION_SUCCESS = new String[]{"2","3","4"};

    /**
     * 删除银行卡信息
     * @param accountId
     * @return
     */
    public int deleteAccountBankCard( Long accountId,Long bankcardId){
        AccountBankcard bankcard=accountBankcardMapper.selectBankcardById(bankcardId,accountId);
        if(bankcard!=null) {
            return accountBankcardMapper.deleteByPrimaryKey(bankcardId);
        }
        return 0;
    }

    /**
     * 银行卡验证通过
     * @param accountId
     * @return
     */
    public int validAccountBankCard( Long accountId,Long bankcardId){
        AccountBankcard bankcard=accountBankcardMapper.selectBankcardById(bankcardId,accountId);
        if(bankcard!=null) {
            return accountBankcardMapper.validBankcardPass(bankcardId,accountId);
        }
        return 0;
    }


    /**
     * 获取账户银行卡列表信息
     * @param accountId
     * @return
     */
    @Override
    public List<AccountBankcard> getBankCardList(Long accountId,Integer isPublic){
        AccountBankcard card=new AccountBankcard();
        card.setAccountId(accountId);
        card.setIsPublic(isPublic);
        List<AccountBankcard> cardList = accountBankcardMapper.select(card);
        List<AccountBankcard> cardNewList=new ArrayList<AccountBankcard>();
        if(!CollectionUtils.isEmpty(cardList)){
            for(AccountBankcard bankcard:cardList){
                bankcard.setBankcardNo(org.apache.commons.lang3.StringUtils.substring(bankcard.getBankcardNo(),bankcard.getBankcardNo().length()-4));
                cardNewList.add(bankcard);
            }
            return cardNewList;
        }
        return cardList;
    }

    /**
     * 获取账户银行卡列表信息
     * @param accountId
     * @return
     */
    @Override
    public List<AccountBankcard> getUsedBankCardList(Long accountId){
        List<AccountBankcard> cardList = accountBankcardMapper.selectUsedBankcardByAccountId(accountId);
        List<AccountBankcard> cardNewList=new ArrayList<AccountBankcard>();
        if(!CollectionUtils.isEmpty(cardList)){
            for(AccountBankcard bankcard:cardList){
                bankcard.setBankcardNo(org.apache.commons.lang3.StringUtils.substring(bankcard.getBankcardNo(),bankcard.getBankcardNo().length()-4));
                cardNewList.add(bankcard);
            }
            return cardNewList;
        }
        return cardList;
    }

    /**
     * 获取资金账户银行卡详情
     * @param accountBankId
     * @return
     */
    public AccountBankcard findAccountBankById(Long accountBankId) {
        return accountBankcardMapper.selectByPrimaryKey(accountBankId);
    }

    /**
     * 更改默认银行卡
     *
     * @param accountId
     * @param accountBankcardId
     * @return
     */
    public int changeDefaultUseBankcard(Long accountId,Long accountBankcardId){
        accountBankcardMapper.updateNoDefault(accountId);
        AccountBankcard accountBankcard =  new AccountBankcard();
        accountBankcard.setId(accountBankcardId);
        accountBankcard.setIsDefault("true");
        return accountBankcardMapper.updateByPrimaryKeySelective(accountBankcard);
    }

    /**
     * 设置联行号与支行名称
     * @param accountBankcardSetUBankCodeAndNameDto
     * @return
     */
    @Override
    public int setUnionBankCodeAndName(AccountBankcardSetUBankCodeAndNameDto accountBankcardSetUBankCodeAndNameDto) {
        AccountBankcard accountBankcard = new AccountBankcard();
        accountBankcard.setId(accountBankcardSetUBankCodeAndNameDto.getAccountBankcardId());
        accountBankcard.setBankUnionName(accountBankcardSetUBankCodeAndNameDto.getBankUnionName());
        accountBankcard.setBankUnionCode(accountBankcardSetUBankCodeAndNameDto.getBankUnionCode());
        return accountBankcardMapper.updateByPrimaryKeySelective(accountBankcard);
    }

    /**
     * //TODO 这里需要考虑其他银行的情况
     * 添加企业银行账户
     * @param accountBankcardDto
     */
    @Override
    public long addCompanyBankCard(String userCode,AccountBankcardDto accountBankcardDto) {
        //校验银行卡号格式
        checkBankcardNoFormat(accountBankcardDto.getBankcardNo());
        Long accountId=accountService.findAccountIdByUserCode(userCode);
        accountBankcardDto.setAccountId(accountId);
        //验证下是否为个人银行卡类型
        final BankcardBin bankcardBin = bankcardBinService.findBankcardBinByCardNum(accountBankcardDto.getBankcardNo());
        if(null != bankcardBin){
            //给出错误提示：该卡为个人银行卡，点击进入个人银行卡填写页面
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_IS_PERSON,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_IS_PERSON));
        }
        //验证该资金账号是否已经将该卡添加了(校验所有的，不管有没有验证通过)
        checkIsExistsAll(accountId,accountBankcardDto.getBankcardNo());
        //先验证账户名与卡号真实性
        boolean isRight=validateBankcard(accountBankcardDto.getBankcardNo(),accountBankcardDto.getBankAccountName());
        if(!isRight){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_NOT_CORRECT,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_NOT_CORRECT));
        }
        //保存到数据库
        AccountBankcard accountBankcard = new AccountBankcard();
        BeanUtils.copyProperties(accountBankcardDto,accountBankcard);
        accountBankcard.setIsPublic(COMPANY_BANK_ACCOUNT);
        //设置logo图片
        accountBankcard.setLogo(channelService.findLogoByBankCode(accountBankcard.getBankCode()));
        accountBankcard.setBankcardDigits(accountBankcard.getBankcardNo().length());
        accountBankcardMapper.insertSelective(accountBankcard);
        //打一笔随机款(得到DEAL_TYPE)
        transferRandomMoney(accountBankcard);
        //等待定时任务去查询是否打款成功
        return accountBankcard.getId();
    }

    @Override
    public void verifyCompanyBankcard(String userCode,AccountCompanyBankcardVerifyDto accountCompanyBankcardVerifyDto) {
        Long accountId = accountService.findAccountIdByUserCode(userCode);
        Long accountBankcardId = accountCompanyBankcardVerifyDto.getAccountBankcardId();
        AccountBankcard accountBankcard = accountBankcardMapper.selectByPrimaryKey(accountBankcardId);
        if(null == accountBankcard){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_NOT_EXISTS, localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_NOT_EXISTS));
        }
        //不能验证别人的卡
        if(accountBankcard.getAccountId().longValue() != accountId.longValue()){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_CANNOT_VERIFY_NOT_BELONG_YOU, localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_CANNOT_VERIFY_NOT_BELONG_YOU));
        }
        //如果已经验证成功了，无须再验证
        if(VALID_SUCCESS == accountBankcard.getValidStatus().intValue()){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_AREADY_VALID, localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_AREADY_VALID));
        }
        int nowValidCount = accountBankcard.getValidCount();
        AccountBankcard accountBankcard4Update = new AccountBankcard();
        accountBankcard4Update.setId(accountBankcardId);
        accountBankcard4Update.setValidCount(nowValidCount+1);
        //大于3次直接报添加银行卡失败
        if(nowValidCount >= INPUT_VALID_AMOUNT_ERR_TIMES){
            accountBankcardMapper.updateByPrimaryKeySelective(accountBankcard4Update);
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_ADD_ERR_WRONG_TO_MUCH, localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_ADD_ERR_WRONG_TO_MUCH));
        }
        try {
            if (accountBankcard.getValidAmount().compareTo(accountCompanyBankcardVerifyDto.getValidAmount()) != 0) {
                if (INPUT_VALID_AMOUNT_ERR_TIMES - nowValidCount-1 <= 0) {
                    throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_ADD_ERR, localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_ADD_ERR));
                } else {
                    throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_VALID_AMOUNT_INPUT_ERR, localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_VALID_AMOUNT_INPUT_ERR, new Object[]{INPUT_VALID_AMOUNT_ERR_TIMES - nowValidCount - 1}));
                }
            } else {
                //若金额填写正确了，还需再校验下，该账户是否已经添加过同一个银行账号了（即所谓的银行卡号）,若已经添加过了，则不允许再次添加
                checkIsExistsOnlyValid(accountId,accountBankcard.getBankcardNo());
                accountBankcard4Update.setValidStatus(VALID_SUCCESS);
            }
        }finally {
            accountBankcardMapper.updateByPrimaryKeySelective(accountBankcard4Update);
        }
    }

    /**
     * 给账户打一笔随机款
     * @param accountBankcard
     */
    private void transferRandomMoney(AccountBankcard accountBankcard) {
        CCB6W8020TxReq ccb6W8020TxReq = new CCB6W8020TxReq();
        ccb6W8020TxReq.setCUST_ID(ccbPayConfigStorage.getWlpt().getString("CUST_ID"));
        ccb6W8020TxReq.setUSER_ID(ccbPayConfigStorage.getWlpt().getString("USER_ID"));
        ccb6W8020TxReq.setPASSWORD(ccbPayConfigStorage.getWlpt().getString("PASSWORD"));
        final String requestSn = serialNumberUtils.getBankRequestSn();
        ccb6W8020TxReq.setREQUEST_SN(requestSn);

        CCB6W8020TxReqBody ccb6W8020TxReqBody = new CCB6W8020TxReqBody();
        final String randomMoney = String.format("%.2f",RandomUtils.nextDouble(0.01D,verifyRandomMoneyUpLimit));
        ccb6W8020TxReqBody.setAMOUNT(randomMoney);
        ccb6W8020TxReqBody.setRECV_ACC_NAME(accountBankcard.getBankAccountName());
        ccb6W8020TxReqBody.setRECV_ACCNO(accountBankcard.getBankcardNo());
        ccb6W8020TxReqBody.setRECV_OPENACC_DEPT(accountBankcard.getBankUnionName());
        ccb6W8020TxReqBody.setRECV_UBANKNO(accountBankcard.getBankUnionCode());
        ccb6W8020TxReqBody.setUSEOF("验证");
        ccb6W8020TxReqBody.setPAY_ACCNO(ccbPayConfigStorage.getWlpt().getString("PAY_ACCNO"));
        ccb6W8020TxReq.setTxBody(ccb6W8020TxReqBody);
        CCB6W8020TxRes ccb6W8020TxRes = ccbWlptUtils.postForCCBWlpt(ccb6W8020TxReq, CCB6W8020TxRes.class);

        final String dealType = ccb6W8020TxRes.getTxBody().getDEAL_TYPE();
        boolean transferSuccess = transferSuccess(ccb6W8020TxRes);
        AccountBankcard accountBankcard4Update = new AccountBankcard();
        if(transferSuccess){
            accountBankcard4Update.setId(accountBankcard.getId());
            accountBankcard4Update.setValidAmount(new BigDecimal(randomMoney));
        }
        accountBankcard4Update.setRequestSn(requestSn);
        accountBankcardMapper.updateByPrimaryKeySelective(accountBankcard4Update);
    }

    private boolean transferSuccess(CCB6W8020TxRes ccb6W8020TxRes){
        if(!RETURN_CODE_SUCCESS.equals(ccb6W8020TxRes.getRETURN_CODE())){
            log.error("打验证款失败,银行返回信息：{}",ccb6W8020TxRes.getRETURN_MSG());
            return false;
        }
        for(String dealTypeTmp: TRANSACTION_SUCCESS ){
            if(dealTypeTmp.equals(ccb6W8020TxRes.getTxBody().getDEAL_TYPE())){
                return true;
            }
        }
        return false;
    }

    /**
     * 校验是否存在某张银行卡（只查有验证通过的）
     * @param accountId
     * @param bankcardNo
     */
    public void checkIsExistsOnlyValid(Long accountId, String bankcardNo){
        int count = accountBankcardMapper.selectCountByAccountIdAndBankcardNo(accountId,bankcardNo);
        if(count >= 1){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_AREADY_EXISTS,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_ALREAD_EXISTS));
        }
    }

    /**
     * 校验是否存在某张银行卡（不管有没有被验证通过）
     * @param accountId
     * @param bankcardNo
     */
    public void checkIsExistsAll(Long accountId, String bankcardNo){
        int count = accountBankcardMapper.selectCountAllByAccountIdAndBankcardNo(accountId,bankcardNo);
        if(count >= 1){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_AREADY_EXISTS,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_ALREAD_EXISTS));
        }
    }

    /**
     * 添加个人银行账户
     * @param accountBankcardDto
     * @return
     */
    @Override
    public long addPersonalBankCard(String userCode,AccountBankcardDto accountBankcardDto) {
        //校验银行卡号格式
        checkBankcardNoFormat(accountBankcardDto.getBankcardNo());
        accountBankcardDto.setIsPublic(BankcardTypeEnum.PERSONEL.getId());
        //TODO 这里后续需要改的
        Long accountId=accountService.findAccountIdByUserCode(userCode);
        accountBankcardDto.setAccountId(accountId);
        final BankcardBin bankcardBin = bankcardBinService.findBankcardBinByCardNum(accountBankcardDto.getBankcardNo());
        if(null == bankcardBin){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_NOT_CORRECT,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_NOT_CORRECT));
        }
        boolean isRight=validateBankcard(accountBankcardDto.getBankcardNo(),accountBankcardDto.getBankAccountName());
        if(isRight) {
            AccountBankcard accountBankcard = new AccountBankcard();
            BeanUtils.copyProperties(accountBankcardDto,accountBankcard);
            accountBankcard.setBankCode((bankcardBin.getBankId()+"").substring(0,3));
            accountBankcard.setBankName(bankService.findBankNameByBankCode(accountBankcard.getBankCode()));
            accountBankcard.setCardType(bankcardBin.getCardType());
            //添加银行logo图片
            accountBankcard.setLogo(channelService.findLogoByBankCode(accountBankcard.getBankCode()));
            //检查该银行卡是否已经被添加过(只查询验证过的,当然个人的只要添加到数据库里的，都是验证通过的)
            checkIsExistsOnlyValid(accountId, accountBankcardDto.getBankcardNo());
            accountBankcard.setValidStatus(VALID_SUCCESS);
            accountBankcard.setBankcardDigits(accountBankcard.getBankcardNo().length());
            accountBankcardMapper.insertSelective(accountBankcard);
            return accountBankcard.getId();
        }else{
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_NOT_CORRECT,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_NOT_CORRECT));
        }
    }

    private boolean validateBankcard(String bankcardNo,String bankAccountName){
        CCB6W1101TxReq req=new CCB6W1101TxReq();
        req.setCUST_ID(ccbPayConfigStorage.getWlpt().getString("CUST_ID"));
        req.setUSER_ID(ccbPayConfigStorage.getWlpt().getString("USER_ID"));
        req.setPASSWORD(ccbPayConfigStorage.getWlpt().getString("PASSWORD"));
        CCB6W1101TxReqBody reqBody=new CCB6W1101TxReqBody();
        reqBody.setACC_NO(bankcardNo);
        reqBody.setACC_NAME(bankAccountName);
        req.setTxBody(reqBody);
        req.setREQUEST_SN(System.currentTimeMillis()+"");
        CCB6W1101TxRes res= ccbWlptUtils.postForCCBWlpt(req,CCB6W1101TxRes.class);
        if("000000".equals(res.getRETURN_CODE())){
            String isRight = res.getTxBody().getIS_RIGHT();
            if("0".equals(isRight)){
                return true;
            }else if("1".equals(isRight)){
                return false;
            }
        }
        return false;
    }

    private void checkBankcardNoFormat(final String bankcardNo){
        //先验证格式
        Matcher matcher = BANKCARD_NO_REGEX.matcher(bankcardNo);
        if(!matcher.find()){
            throw new BusinessException(ExceptionCodeConstants.ACCOUNT_BANKCARD_NOT_CORRECT,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.ACCOUNT_BANKCARD_NOT_CORRECT));
        }
    }
}